﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using ttg_internal.Utilities.PipelineManager.Diagram;

namespace ttg_internal.Utilities.PipelineManager.Helpers
{
    public static class CanvasHelper
    {
        // Dependency properties
        public static readonly DependencyProperty ChildrenProperty = DependencyProperty.RegisterAttached("Children", typeof(IEnumerable), typeof(CanvasHelper), new PropertyMetadata(OnChildenChanged));

        // Private fields
        private static readonly Dictionary<object, Canvas> CollectionMapping = new Dictionary<object, Canvas>();

        public static IEnumerable GetChildren(Canvas obj)
        {
            return (IEnumerable)obj.GetValue(ChildrenProperty);
        }

        public static void SetChildren(Canvas obj, IEnumerable value)
        {
            obj.SetValue(ChildrenProperty, value);
        }

        private static void OnChildenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (e.OldValue != null)
            {
                Debug.Assert(CollectionMapping.ContainsKey(e.OldValue));
                CollectionMapping.Remove(e.OldValue);
            }

            var oldValue = e.OldValue as INotifyCollectionChanged;

            if (oldValue != null)
            {
                oldValue.CollectionChanged -= OnChildrenCollectionChanged;
            }

            if (e.NewValue != null)
            {
                Debug.Assert(d is Canvas);
                CollectionMapping.Add(e.NewValue, (Canvas)d);

                OnChildrenCollectionChanged(e.NewValue, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
            }

            var newValue = e.NewValue as INotifyCollectionChanged;

            if (newValue != null)
            {
                newValue.CollectionChanged += OnChildrenCollectionChanged;
            }
        }

        private static void OnChildrenCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Debug.Assert(CollectionMapping.ContainsKey(sender));
            Canvas canvas = CollectionMapping[sender];

            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add:
                    foreach (UIElement element in e.NewItems.Cast<UIElement>().Reverse())
                    {
                        canvas.Children.Insert(e.NewStartingIndex, element);
                    }
                    break;

                case NotifyCollectionChangedAction.Remove:
                    foreach (var _ in e.OldItems)
                    {
                        canvas.Children.RemoveAt(e.OldStartingIndex);
                    }
                    break;

                case NotifyCollectionChangedAction.Replace:
                    throw new NotSupportedException("NotifyCollectionChangedAction.Replace is not supported");

                case NotifyCollectionChangedAction.Reset:
                    canvas.Children.Clear();
                    Debug.Assert(sender is IEnumerable);

                    foreach (UIElement element in (IEnumerable)sender)
                    {
                        canvas.Children.Add(element);
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
            }

            var designerCanvas = canvas as DesignerCanvas;

            if (designerCanvas != null)
            {
                designerCanvas.AutoAlign = true;
            }
        }
    }
}
